// 封装迭代器方法
function iterationMethod() {
  // 获取原始数据对象target
  const target = this.raw
  // 获取原始迭代器方法
  const itr = target[Symbol.iterator]()

  const wrap = (val) => typeof val === 'object' && val !== null ? reactive(val) : val
  track(target, ITERATE_KEY)
  return {
    next() {
      const { value, done } = itr.next()
      return {
        value: value ? [wrap(value[0]), wrap(value[1])] : value,
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

// 封装values方法
function valuesIterationMethod() {
  // 获取原始数据对象target
  const target = this.raw
  // 通过target.values获取原始迭代器方法
  const itr = target.values()
  // 包装成响应式数据
  const wrap = (val) => typeof val === 'object' && val !== null ? reactive(val) : val

  // 追踪依赖
  track(target, ITERATE_KEY)

  // 返回
  return {
    next() {
      const { value, done } = itr.next()
      return {
        // value是值，而非键值对，所以只需要包裹value即可
        value: wrap(value),
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

// 封装keys方法
function keysIterationMethod() {
  // 获取原始数据对象target
  const target = this.raw
  // 通过target.values获取原始迭代器方法
  const itr = target.keys()
  // 包装成响应式数据
  const wrap = (val) => typeof val === 'object' && val !== null ? reactive(val) : val

  // 追踪依赖
  track(target, MAP_KEY_ITERATE_KEY)

  // 返回
  return {
    next() {
      const { value, done } = itr.next()
      return {
        // value是值，而非键值对，所以只需要包裹value即可
        value: wrap(value),
        done
      }
    },
    [Symbol.iterator]() {
      return this
    }
  }
}

const mutableInstrumentations = {
  add(key) {
    const target = this.raw
    const hadKey = target.has(key)
    let res
    if (!hadKey) {
      res = target.add(key)
      trigger(target, key, 'ADD')
    }
    return res
  },
  delete(key) {
    const target = this.raw
    const hadKey = target.has(key)
    const res = target.delete(key)
    if (hadKey) {
      trigger(target, key, 'DELETE')
    }
    return res
  },
  get(key) {
    // 获取原始对象
    const target = this.raw
    // 判断读取的key是否存在
    const had = target.has(key)
    // 追踪以来，建立响应联系
    track(target, key)
    if (had) {
      const res = target.get(key)
      return typeof res === 'object' ? reactive(res) : res
    }
  },
  set(key, value) {
    const target = this.raw
    const had = target.has(key)
    const oldValue = target.get(key)
    const rawValue = value.raw | value
    target.set(key, rawValue)
    if (!had) {
      trigger(target, key, 'ADD')
    } else if (oldValue !== value || (oldValue === oldValue && value === value)){
      trigger(target, key, 'SET')
    }
  },
  forEach(callback, thisArg) {
    const wrap = (val) => typeof val === 'object' ? reactive(val) : val
    const target = this.raw
    track(target, ITERATE_KEY)
    target.forEach((v, k) => {
      callback.call(thisArg, wrap(v), wrap(k), this)
    })
  },
  entries: iterationMethod,
  values: valuesIterationMethod,
  keys: keysIterationMethod,
  [Symbol.iterator]:iterationMethod
}
